package mvc.bezier;


import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import javax.media.opengl.glu.GLU;


import org.geom.Point2D;
import org.geom.Vector3D;
import org.geom.render.Engine2D;

public class BezierMouseController2D extends BezierSetter 
implements MouseListener, MouseMotionListener{

	//---------------------------------------------------------------------- class var
	private BezierView2D view;
	private BezierModel model;
	
	private Point2D mouseDown = new Point2D();
	private int deltax; // mouse movement delta
	private int deltay;

	public Vector3D controlPointInDrag;
		
	public BezierMouseController2D(BezierModel model, BezierView2D view2d) {//, Block block) {
		super(model);
		this.view = view2d;
		this.model = model;
	}
	
	//---------------------------------------------------------------------- interface

	Vector3D pre;
	public void mousePressed(MouseEvent e) {
		mouseDown = new Point2D(e.getX(), e.getY());
		if(controlPointInDrag == null) pre = view.getTranslate();
		else pre = controlPointInDrag.duplicate();
		//mouseDragged(e);
	}

	public void mouseDragged(MouseEvent e) {
		float s = view.getScale().x;
		
		deltax = e.getX() - (int)mouseDown.x;
		deltay = e.getY() - (int)mouseDown.y;
		
		if(controlPointInDrag != null) {
			if (view.planeString==Engine2D.X) { 
				controlPointInDrag.y = pre.y + deltax*s;
				controlPointInDrag.z = pre.z - deltay*s;
			}if(view.planeString==Engine2D.Y) {
				controlPointInDrag.x = pre.x + deltax*s;
				controlPointInDrag.z = pre.z - deltay*s;
			}if(view.planeString==Engine2D.Z) {
				controlPointInDrag.x = pre.x + deltax*s;
				controlPointInDrag.y = pre.y - deltay*s;
			}
			model.notifyAllViews();
		}
		else  {
			//System.out.println("bezier mouse controller 2d > mousedragged, deltaxy "+ deltax +" "+ deltay);
			view.setTranslate(new Vector3D( (pre.x + deltax)*s, (pre.y + deltay)*s, 0));
		}
		view.repaint();
	}
	
	public void mouseReleased(MouseEvent e) {
		controlPointInDrag = null;
	}
		
	//---------------------------------------------------------------------- privates
	
	private Vector3D checkMouseOnControlPoints(float mouseX, float mouseY) {
		int i=0;
		float d = 0;
		ArrayList<Vector3D> pts = model.getControlPoints();
		Vector3D drawedPoint = new Vector3D(); // remember! draed point are biased in 2d view!
		
		for(Vector3D p : pts) {
			
			if (view.planeString==Engine2D.X) { 
				drawedPoint.x = p.y; 
				drawedPoint.y = p.z;
			} if (view.planeString==Engine2D.Y) {
				drawedPoint.x = p.x; 
				drawedPoint.y = p.z;
			} if (view.planeString==Engine2D.Z) {
				drawedPoint.x = p.x; 
				drawedPoint.y = p.y;
			}
			
			d = checkMouseOnPoint(mouseX, mouseY, drawedPoint, view.glu);
			i++;
			//System.out.println("BezierMouseController2D > point is: \n\t"+i+" "+d);
			if (d<10) {
				return p;
			}
		}		
		//System.out.println("no point selected");
		return null;
	}
	
	private float checkMouseOnPoint(float mouseX, float mouseY, Vector3D p, GLU glu) {
		/**
		 * 
		 * RAY PICKING
		 * 
		 * */
		
		int x = (int) mouseX, 
			y = (int) mouseY;
	    int realy = 0;
	    
	    int viewport[] = view.viewport;
	    double model_view[] = view.model_view;
	    double projection[] = view.projection;
	    double wcoord[] = new double[4];// wx, wy, wz;// returned xyz coords
	    
	    realy = viewport[3] - y;
	    //System.out.println("Coordinates at cursor are (" + x + ", " + realy);
	    
	    glu.gluUnProject( x,  realy, 0,
	            model_view, 0, projection, 0, viewport, 0, wcoord, 0);
	    //System.out.println("World coords at z=0.0 are ( "+ wcoord[0] + ", " + wcoord[1] + ", " + wcoord[2]+ ")");
	    Vector3D x1 = new Vector3D(wcoord[0], wcoord[1], wcoord[2]); 
		
	    glu.gluUnProject( x,  realy, 1, 
            model_view, 0, projection, 0, viewport, 0, wcoord, 0);
        //System.out.println("World coords at z=1.0 are ("+ wcoord[0] + ", " + wcoord[1] + ", " + wcoord[2]+ ")");
        Vector3D x2 = new Vector3D(wcoord[0], wcoord[1], wcoord[2]);

        // collision detection between ray x1-x2 and point x0
        Vector3D p_minus_x1 = p.minus(x1);
        Vector3D p_minus_x2 = p.minus(x2);
        float d = p_minus_x1.crossSelf(p_minus_x2).mag() /
        	(x2.minus(x1)).mag();
	    
		return d;
	}

	@Override
	public void mouseClicked(MouseEvent e) {}
	@Override
	public void mouseEntered(MouseEvent e) {}
	@Override
	public void mouseExited(MouseEvent e) {}
	@Override
	public void mouseMoved(MouseEvent e) {
		view.repaint();
		controlPointInDrag = checkMouseOnControlPoints(e.getX(), e.getY());
	}
}
